from machine import Pin, SPI, PWM
import st7789
import utime
import urandom

# 硬件初始化
pwm = PWM(2, Pin(5))
pwm.init(freq=2442, duty=50)
pwm.duty(0)

spi = SPI(0, baudrate=40000000, polarity=1, phase=0, bits=8, endia=0,
          sck=Pin(6), mosi=Pin(8))
display = st7789.ST7789(
    spi, 240, 240,
    reset=Pin(11, func=Pin.GPIO, dir=Pin.OUT),
    dc=Pin(7, func=Pin.GPIO, dir=Pin.OUT),
    direction=st7789.NORMAL
)
display.init()

# 按键初始化 - 使用您提供的语法
KEY_A = Pin(9)
KEY_A.init(Pin.IN)
KEY_A.pull(Pin.PULL_DOWN)

KEY_B = Pin(1)
KEY_B.init(Pin.IN)
KEY_B.pull(Pin.PULL_DOWN)

KEY_C = Pin(0)
KEY_C.init(Pin.IN)
KEY_C.pull(Pin.PULL_DOWN)

KEY_D = Pin(14)
KEY_D.init(Pin.IN)
KEY_D.pull(Pin.PULL_DOWN)

# 颜色定义
WHITE = st7789.color565(245, 245, 247)
BLACK = st7789.color565(29, 29, 31)
GREEN = st7789.color565(140, 193, 82)
RED = st7789.color565(218, 68, 83)
YELLOW = st7789.color565(250, 250, 210)

# 游戏常量
TOTAL_ROUNDS = 19
RESPONSE_MS = 1000
TRIANGLE_SIZE = 20
BETWEEN_ROUNDS_DELAY = 500
DEBOUNCE_DELAY = 50  # 按键防抖动延迟

# 游戏状态
STATE_MENU = 0
STATE_GAME = 1
STATE_OVER = 2

# 位置与对应按键
POSITIONS = [
    [10, 240-TRIANGLE_SIZE-10, KEY_A, "A"],
    [240-TRIANGLE_SIZE-10, 240-TRIANGLE_SIZE-10, KEY_B, "B"],
    [10, 10, KEY_C, "C"],
    [240-TRIANGLE_SIZE-10, 10, KEY_D, "D"]
]

# 游戏变量
current_state = STATE_MENU
score = 0
current_round = 0
current_position = None
round_start_time = 0
input_received = False
last_button_states = [0, 0, 0, 0]
last_state_change = 0  # 用于状态切换防抖动

# 播放声音函数
def play_sound(freq, duration):
    try:
        pwm.duty(50)
        pwm.freq(freq)
        utime.sleep(duration)
    finally:
        pwm.duty(0)  # 确保声音最终会关闭

# 绘制三角形 - 使用线段代替多边形，解决没有poly方法的问题
def draw_triangle(x, y, size, color):
    # 计算三角形三个顶点
    x1 = x + size // 2
    y1 = y
    x2 = x
    y2 = y + size
    x3 = x + size
    y3 = y + size
    
    # 绘制三条边
    display.line(x1, y1, x2, y2, color)  # 顶部到左下
    display.line(x2, y2, x3, y3, color)  # 左下到右下
    display.line(x3, y3, x1, y1, color)  # 右下到顶部
    
    # 填充三角形内部（使用多条水平线填充）
    for i in range(size):
        # 计算每一行的左右边界
        left = x + (i * size) // (2 * size)
        right = x + size - (i * size) // (2 * size)
        display.line(left, y + i, right, y + i, color)

# 清空屏幕
def clear_screen(color):
    display.fill(color)

# 绘制文本
def draw_text(x, y, text, color, bg_color, size):
    display.draw_string(x, y, text, color=color, bg=bg_color, size=size)

# 按键状态更新与检测
def check_button_press(button, index):
    current_state = button.value()
    if current_state == 1 and last_button_states[index] == 0:
        # 检测到上升沿，等待防抖动
        utime.sleep_ms(DEBOUNCE_DELAY)
        if button.value() == 1:  # 确认按键仍按下
            last_button_states[index] = 1
            return True
    elif current_state == 0:
        last_button_states[index] = 0
    return False

# 主菜单处理
def handle_menu():
    global current_state, score, current_round, last_state_change
    
    # 确保只在状态刚进入时绘制一次界面
    if utime.ticks_diff(utime.ticks_ms(), last_state_change) < 100:
        clear_screen(WHITE)
        draw_text(40, 80, "Triangle", BLACK, WHITE, 3)
        draw_text(70, 110, "Game", BLACK, WHITE, 3)
        draw_text(20, 180, "Press A to Start", BLACK, WHITE, 1)
    
    # 检测A键按下
    if check_button_press(KEY_A, 0):
        current_state = STATE_GAME
        score = 0
        current_round = 0
        play_sound(1175, 0.1)
        last_state_change = utime.ticks_ms()  # 记录状态变化时间

# 游戏处理
def handle_game():
    global current_state, score, current_round, current_position
    global round_start_time, input_received, last_state_change
    
    # 状态进入时初始化
    if utime.ticks_diff(utime.ticks_ms(), last_state_change) < 100:
        current_position = None
        input_received = False
        current_round = 0
    
    # 检查是否完成所有轮次
    if current_round >= TOTAL_ROUNDS:
        current_state = STATE_OVER
        last_state_change = utime.ticks_ms()
        return
    
    # 准备新一轮
    if current_position is None:
        clear_screen(WHITE)
        # 确保随机数真正随机
        urandom.seed(utime.ticks_ms() + current_round)
        pos_idx = urandom.getrandbits(2)  # 0-3的随机数
        current_position = POSITIONS[pos_idx]
        round_start_time = utime.ticks_ms()
        input_received = False
        current_round += 1
        return
    
    # 绘制当前三角形和游戏信息
    x, y, _, key_name = current_position
    draw_triangle(x, y, TRIANGLE_SIZE, BLACK)
    # 使用字符串拼接代替f-string
    draw_text(10, 10, "Round: " + str(current_round) + "/" + str(TOTAL_ROUNDS), 
             BLACK, WHITE, 1)
    draw_text(10, 30, "Score: " + str(score), BLACK, WHITE, 1)
    
    # 计算剩余时间
    elapsed = utime.ticks_diff(utime.ticks_ms(), round_start_time)
    remaining = max(0, RESPONSE_MS - elapsed)
    draw_text(150, 10, "Time: " + str(remaining//100) + "ms", BLACK, WHITE, 1)
    draw_text(10, 220, "Press " + key_name, BLACK, WHITE, 1)  # 显示需要按的键
    
    # 检测按键输入
    if not input_received:
        x_pos, y_pos, target_key, key_name = current_position
        
        # 检查目标按键是否按下
        if check_button_press(target_key, POSITIONS.index(current_position)):
            input_received = True
            if elapsed < RESPONSE_MS:
                score += 1
                draw_text(70, 120, "Correct!", GREEN, WHITE, 2)
                play_sound(1319, 0.1)
            else:
                draw_text(60, 120, "Too Slow!", RED, WHITE, 2)
                play_sound(880, 0.1)
            
            utime.sleep_ms(BETWEEN_ROUNDS_DELAY)
            current_position = None
    
    # 超时检查
    if not input_received and utime.ticks_diff(utime.ticks_ms(), round_start_time) >= RESPONSE_MS:
        input_received = True
        draw_text(60, 120, "Too Slow!", RED, WHITE, 2)
        play_sound(880, 0.1)
        utime.sleep_ms(BETWEEN_ROUNDS_DELAY)
        current_position = None

# 游戏结束处理
def handle_over():
    global current_state, last_state_change
    
    # 状态进入时绘制界面
    if utime.ticks_diff(utime.ticks_ms(), last_state_change) < 100:
        clear_screen(YELLOW)
        draw_text(40, 60, "Game Over", BLACK, YELLOW, 3)
        # 使用字符串拼接代替f-string
        draw_text(60, 110, "Score: " + str(score) + "/" + str(TOTAL_ROUNDS), 
                 BLACK, YELLOW, 3)
        
        accuracy = (score * 100) // TOTAL_ROUNDS
        draw_text(30, 140, "Accuracy: " + str(accuracy) + "%", BLACK, YELLOW, 2)
        
        if accuracy >= 80:
            draw_text(40, 170, "Excellent!", GREEN, YELLOW, 2)
        elif accuracy >= 60:
            draw_text(40, 170, "Good Job!", BLACK, YELLOW, 2)
        else:
            draw_text(30, 170, "Try Again!", RED, YELLOW, 2)
        
        draw_text(20, 200, "Press A to Restart", BLACK, YELLOW, 1)
    
    # 检测A键重新开始
    if check_button_press(KEY_A, 0):
        current_state = STATE_MENU
        play_sound(1175, 0.1)
        last_state_change = utime.ticks_ms()

# 主循环
while True:
    # 根据当前状态处理
    if current_state == STATE_MENU:
        handle_menu()
    elif current_state == STATE_GAME:
        handle_game()
    elif current_state == STATE_OVER:
        handle_over()
    
    utime.sleep_ms(30)
    